package com.example.shoppinglist;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.koushikdutta.async.future.FutureCallback;
import com.koushikdutta.ion.Ion;
import com.squareup.picasso.Picasso;

import android.app.ActionBar;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.Typeface;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.widget.DrawerLayout;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;

public class ShoppingListActivity extends FragmentActivity {

	public static final String ENTERED_CURRENCY_KEY = "pound";
	private static final String LIST_ID_KEY = "listId";
	private static final String DRAWER_POSITION_KEY = "drawerPosition";

	//this is the data set, this will store the shopping list items that are added to the list,
	//and stores each list. It is the data used by the PagerAdapter.
	private LinkedHashMap<Integer, ShoppingList> allLists; 
	DecimalFormat df = new DecimalFormat("#0.00");

	private ImageLoader imageLoader;
	private DrawerLayout mDrawerLayout;
	private DrawerDynamicListView mDrawerList;
	private ActionBarDrawerToggle mDrawerToggle;
	private CharSequence mTitle;
	private CharSequence mDrawerTitle;
	private DrawerListAdapter mDrawerListAdapter;
	public ShoppingListFragment currentFragment;

	@Override
	protected void onPause() {
		ShoppingListDataSource dataSource = new ShoppingListDataSource(this);
		dataSource.update(allLists);
		super.onPause();
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		//setting the Trolley title to my style
		TextView abTitle = (TextView) findViewById(getResources().getIdentifier("action_bar_title", "id", "android"));
		abTitle.setTextColor(Color.WHITE);
		Typeface type = Typeface.createFromAsset(getAssets(),"fonts/CaviarDreams_Bold.ttf");
		abTitle.setTypeface(type);
		abTitle.setTextSize(getResources().getDimension(R.dimen.action_bar_title));
		//setting action bar colour
		ActionBar bar = getActionBar();
		bar.setBackgroundDrawable(new ColorDrawable(getResources().getColor( SettingsActivity.getColorPref(this))));
		setContentView(R.layout.list_activity);

		//setting up the items in the list with relevant images
		ShoppingListDataSource dataSource = new ShoppingListDataSource(this);
		allLists = dataSource.getShoppingLists();
		imageLoader = new ImageLoader(this, R.dimen.image_height);

		int drawerPosition = 0;
		if(!allLists.keySet().isEmpty()){
			int listId = 0;

			if(savedInstanceState == null){
				List<ShoppingList> shoppingLists = new ArrayList<ShoppingList>(allLists.values());
				int position = (shoppingLists.size()-1);
				listId =  shoppingLists.get(position).getListId();
				drawerPosition = 1;
			}else{
				listId = savedInstanceState.getInt(LIST_ID_KEY);
				drawerPosition = savedInstanceState.getInt(DRAWER_POSITION_KEY);
			}

			currentFragment = new ShoppingListFragment();
			Bundle bundle = new Bundle();
			//giving bundle the position so that the new fragment knows which page it is
			bundle.putInt(ShoppingListFragment.LIST_ID_KEY, listId);
			currentFragment.setArguments(bundle);
			getSupportFragmentManager().beginTransaction()
			.add(R.id.content_frame, currentFragment).commit();
		}

		//setting the drawer's layout and functions etc.
		mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
		mDrawerLayout.requestDisallowInterceptTouchEvent(true);
		mDrawerList = (DrawerDynamicListView) findViewById(R.id.left_drawer);
		ImageView addButton = (ImageView) findViewById(R.id.add_image_drawer);
		imageLoader.displayImage(addButton, R.drawable.ic_action_new, R.color.light_grey, android.R.color.transparent);
		addButton.setOnClickListener(new AddClickListener());
		// Set the adapter for the list view
		mDrawerListAdapter = new DrawerListAdapter(this, R.layout.drawer_list_item);
		mDrawerList.setAdapter(mDrawerListAdapter);
		mDrawerList.setShoppingLists(allLists);
		mDrawerList.setDrawerLayout(mDrawerLayout);
		// Set the list's click listener
		mDrawerList.setOnItemClickListener(new SelectClickListener());
		if(drawerPosition != 0){
			mDrawerList.setItemChecked(drawerPosition, true);
		}
		mTitle = getTitle();
		mDrawerTitle = getResources().getText(R.string.drawer_open);

		//toggle for the drawer options
		mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
				R.drawable.ic_navigation_drawer, R.string.drawer_open, R.string.drawer_close) {

			// Called when a drawer has settled in a completely closed state
			public void onDrawerClosed(View view) {
				super.onDrawerClosed(view);
				getActionBar().setTitle(mTitle);
				invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
			}

			// Called when a drawer has settled in a completely open state
			public void onDrawerOpened(View drawerView) {
				super.onDrawerOpened(drawerView);
				getActionBar().setTitle(mDrawerTitle);
				invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
			}
		};

		// Set the drawer toggle as the DrawerListener
		mDrawerLayout.setDrawerListener(mDrawerToggle);
		PreferenceManager.setDefaultValues(this, R.xml.settings, false);
		getActionBar().setDisplayHomeAsUpEnabled(true);
		getActionBar().setHomeButtonEnabled(true);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu){
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.menu, menu);
		return true;
	}
	
	@Override
	public boolean onOptionsItemSelected(MenuItem item){
		switch(item.getItemId()){
		case R.id.preferences:
			Intent i = new Intent(this, SettingsActivity.class);
			startActivity(i);
		}
		return false;
	}

	@Override
	protected void onSaveInstanceState(Bundle outState) {
		List<ShoppingList> shoppingLists = new ArrayList<ShoppingList>(allLists.values());
		int position = (shoppingLists.size()-1) - (mDrawerList.getCheckedItemPosition()-1);
		if(position < shoppingLists.size()){
			int listId =  shoppingLists.get(position).getListId();
			outState.putInt(LIST_ID_KEY, listId);
			outState.putInt(DRAWER_POSITION_KEY, mDrawerList.getCheckedItemPosition());
			super.onSaveInstanceState(outState);
		}
	}

	@Override
	protected void onPostCreate(Bundle savedInstanceState) {
		super.onPostCreate(savedInstanceState);
		// Sync the toggle state after onRestoreInstanceState has occurred.
		mDrawerToggle.syncState();
	}

	@Override
	public void onConfigurationChanged(Configuration newConfig) {
		super.onConfigurationChanged(newConfig);
		mDrawerToggle.onConfigurationChanged(newConfig);
	}

	public ImageLoader getImageLoader(){
		return imageLoader;
	}

	//this allows the fragment(page) to get the list relevant to them
	public ShoppingList getList(int listId) {
		return allLists.get(listId);
	}

	public void addItemToShoppingList(ShoppingItem enteredItem, int listId) {
		allLists.get(listId).addItem(enteredItem);
		mDrawerListAdapter.notifyDataSetChanged();
	}

	public void addValue(long itemId, BigDecimal cost, int listId){
		allLists.get(listId).getItem(itemId).setCost(cost);
		mDrawerListAdapter.notifyDataSetChanged();
	}

	public void changeName(long itemId, String name, int listId){
		allLists.get(listId).getItem(itemId).setName(name);
		mDrawerListAdapter.notifyDataSetChanged();
	}

	public void deleteAnItem(long itemId, int listId){
		allLists.get(listId).remove(itemId);
		mDrawerListAdapter.notifyDataSetChanged();
	}

	public String getCurrency(int listId){
		return allLists.get(listId).getCurrency();
	}

	public void setCurrency(int listId, String currencyType){
		allLists.get(listId).setCurrency(currencyType);
		mDrawerListAdapter.notifyDataSetChanged();
	}

	public BigDecimal getFunds(int listId){
		return allLists.get(listId).getFunds();
	}

	public void addFunds(int listId, BigDecimal value) {
		allLists.get(listId).setFunds(value);
		mDrawerListAdapter.notifyDataSetChanged();
	}

	public int getColor(int listId){
		return allLists.get(listId).getColour();
	}

	public void setColor(int listId, int color){
		allLists.get(listId).setColour(color);
		mDrawerListAdapter.notifyDataSetChanged();
	}

	public void setDate(int listId, Date date) {
		allLists.get(listId).setDate(date);
		mDrawerListAdapter.notifyDataSetChanged();
	}

	public Date getDate(int listId){
		return allLists.get(listId).getDate();
	}

	public void editListName(String newName, int listId) {
		allLists.get(listId).setListName(newName);
    	mDrawerListAdapter.notifyDataSetChanged();
	}

	public String getListName(int listId){
		return allLists.get(listId).getListName();
	}

	public int newList() {
		//creating a new list and putting it in the right place
		String title = SettingsActivity.getTitlePref(this);
		int color = SettingsActivity.getColorPref(this);
		String currency = SettingsActivity.getCurrencyPref(this);
		Set<Integer> keySet = allLists.keySet();
		int max = 0;
		for(Integer key: keySet){
			if(key.intValue() > max){
				max = key.intValue();
			}
		}
		ArrayList<ShoppingItem> items = new ArrayList<ShoppingItem>();
		ShoppingList shoppingList = new ShoppingList(max+1, BigDecimal.ZERO, color, new Date(), currency, title, items);
		
		
		List<Entry<Integer, ShoppingList>> rest = new ArrayList<Entry<Integer, ShoppingList>>();
		for (Entry<Integer, ShoppingList> entry : allLists.entrySet()) {
			rest.add(entry);
		}
		allLists.clear();
		allLists.put(shoppingList.getListId(), shoppingList);
		for (Entry<Integer, ShoppingList> entry : rest) {
			allLists.put(entry.getKey(), entry.getValue());
		}
		
		ActionBar bar = getActionBar();
		bar.setBackgroundDrawable(new ColorDrawable(getResources().getColor(color)));
		mDrawerListAdapter.rebuildMap();
		mDrawerListAdapter.notifyDataSetChanged();
		return shoppingList.getListId();
	}

	public void deleteList(int listId) {
		//deleting list and taking user to right place
		allLists.get(listId).getItems().clear();
		allLists.remove(listId);
		mDrawerListAdapter.notifyDataSetChanged();
	}

	public class DrawerListAdapter extends BaseAdapter{

		//making a list to make it easier/more relevant to positions.
		private int resource;
		private Context context;
		private DecimalFormat df;
		private HashMap<ShoppingList, Integer> mIdMap = new HashMap<ShoppingList, Integer>();
		private final int INVALID_ID = -1;
		private ArrayList<ShoppingList> shoppingLists;

		public DrawerListAdapter(Context context, int resource) {
			super();
			this.resource = resource;
			shoppingLists = new ArrayList<ShoppingList>(allLists.values());
			this.context = context;
			df = new DecimalFormat("#0.00");
			
			for (int i = 0; i < shoppingLists.size(); ++i) {
				mIdMap.put(shoppingLists.get(i), i);
			}
		}
		
		@Override
		public long getItemId(int position) {
			if (position < 0 || position >= mIdMap.size()) {
				return INVALID_ID;
			}
			ShoppingList item = (ShoppingList) getItem(position);
			return mIdMap.get(item);
		}

		public void rebuildMap() {
			mIdMap.clear();

			shoppingLists = new ArrayList<ShoppingList>(allLists.values());
			for (int i = 0; i < shoppingLists.size(); ++i) {
				mIdMap.put(shoppingLists.get(i), i);
			}
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			ViewHolder holder;
			LayoutInflater inflater = getLayoutInflater();
			if(convertView == null) {
				holder = new ViewHolder();
				convertView = inflater.inflate(resource, parent, false);
				holder.card = (LinearLayout) convertView.findViewById(R.id.list_card);
				holder.circle = (ImageView) convertView.findViewById(R.id.circle_image_drawer);
				holder.name = (TextView) convertView.findViewById(R.id.list_name);
				holder.delete = (ImageView) convertView.findViewById(R.id.remove_list);
				holder.nameDrawer = (TextView) convertView.findViewById(R.id.list_name_drawer);
				holder.date = (TextView) convertView.findViewById(R.id.date_drawer);
				holder.budget = (TextView) convertView.findViewById(R.id.budget_number_drawer);
				holder.total = (TextView) convertView.findViewById(R.id.total_number_drawer);
				holder.cardList = (LinearLayout) convertView.findViewById(R.id.card_list_items);
				convertView.setTag(holder);
			}else{
				holder = (ViewHolder) convertView.getTag();
			}

			//the mini-list label outside list representation
			holder.name.setText(shoppingLists.get(position).getListName());
			//the mini-list's name inside the representation
			holder.nameDrawer.setText(shoppingLists.get(position).getListName());
			String formattedDate = ShoppingListFragment.getCustomDateString(shoppingLists.get(position).getDate());
			holder.date.setText(formattedDate);
			String currency = shoppingLists.get(position).getCurrency();
			BigDecimal totalCost = BigDecimal.ZERO;
			for (ShoppingItem item2 : shoppingLists.get(position).getItems()) {
				if (item2.getCost() != null) {
					totalCost = totalCost.add(item2.getCost());
				}
			}
			holder.total.setText(currency + df.format(totalCost));
			holder.budget.setText(currency + df.format(shoppingLists.get(position).getFunds()));
			int color = shoppingLists.get(position).getColour();
			//for the big add button
			imageLoader.displayImage(holder.circle, R.drawable.ic_action_new, R.color.light_grey, color);
			//holds one mini list, clear data to keep the card up to date
			//and to keep the card relevant to the right list for example when scrolling up and down
			//it recycles the cards so the right data needs to be in each
			holder.cardList.removeAllViews();
			//only need the top 3 as the top 3 items are all that can be seen
			int i = 0;
			for (ShoppingItem item : shoppingLists.get(position).getItems()) {
				if (i == 4) {
					break;
				}
				View singleItem = inflater.inflate(R.layout.item_layout_drawer, parent, false);
				ImageView circleImage = (ImageView) singleItem.findViewById(R.id.circle_image);
				TextView name = (TextView) singleItem.findViewById(R.id.name_edit);
				TextView cost = (TextView) singleItem.findViewById(R.id.cost_edit);
				name.setText(item.getName());
				cost.setText(currency + df.format(item.getCost()));

				getUrl(item, circleImage);
				
				holder.cardList.addView(singleItem);
				i++;
			}
			holder.delete.setOnClickListener(new DeleteClickListener(shoppingLists.get(position).getListId(), position));
			return convertView;
		}

		private void getUrl(ShoppingItem item, ImageView imageView) {
			// simple method as there is no recycling in this one
			//if the first thing the user does is swipe through the drawer
			//then need to download the mini images for the cards before the big lists have done it

			if(item.getUrl() == null || item.getUrl().isEmpty()){
				Ion.with(context)
				.load(String.format("https://ajax.googleapis.com/ajax/services/search/images?v=1.0&q=%s&start=%d&imgsz=medium", Uri.encode(item.getName()), 1))
				// get the results as json
				.asJsonObject()
				.setCallback(new ItemUrlCallBack(item, imageView));
			}else{
				Picasso.with(context)
				.load(item.getUrl())
				.transform(new CircleTransform())
				.placeholder(R.drawable.update)
				.error(R.drawable.high_importance)
				.into(imageView);
			}
		}

		public class ItemUrlCallBack implements FutureCallback<JsonObject> {
			private ShoppingItem item;
			private ImageView imageView;

			public ItemUrlCallBack(ShoppingItem item, ImageView imageView){
				this.item = item;
				this.imageView = imageView;
			}

			@Override
			public void onCompleted(Exception e, JsonObject result) {
				try {
					if(e != null){
						throw e;
					}
					// find the results and load
					JsonArray results = result.getAsJsonObject("responseData").getAsJsonArray("results");
					item.setUrl(results.get(0).getAsJsonObject().get("url").getAsString());

					Picasso.with(context)
					.load(item.getUrl())
					.transform(new CircleTransform())
					.placeholder(R.drawable.update)
					.error(R.drawable.high_importance)
					.into(imageView);
				}
				catch (Exception ex) {
				}
			}
		}

		@Override
		public int getCount() {
			return shoppingLists.size();
		}

		public class ViewHolder{
			public LinearLayout card;
			public LinearLayout cardList;
			public TextView total;
			public TextView budget;
			public TextView date;
			public TextView nameDrawer;
			public ImageView delete;
			public ImageView circle;
			public TextView name;
		}

		@Override
		public Object getItem(int position) {
			if(allLists.isEmpty()){
				return null;
			}
			return shoppingLists.get(position);
		}

		@Override
		public void notifyDataSetChanged() {
			//getting hold of the data so can change the view to the correct thing
			//the drawer uses objects(like everything uses allLists) 
			//but objects doesn't get changed like allLists does so we have to keep it up to date

			shoppingLists = new ArrayList<ShoppingList>(allLists.values());
			super.notifyDataSetChanged();
		}
	}

	public class SelectClickListener implements OnItemClickListener {
		//to pick a list in the drawer
		@Override
		public void onItemClick(AdapterView<?> arg0, View arg1, int position, long listId) {
			// Create fragment and give it an argument specifying the article it should show
			currentFragment = new ShoppingListFragment();
			Bundle args = new Bundle();
			ShoppingList list = (ShoppingList) mDrawerListAdapter.getItem(position);
			args.putInt(ShoppingListFragment.LIST_ID_KEY, list.getListId());
			currentFragment.setArguments(args);

			FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

			// Replace whatever is in the fragment_container view with this fragment,
			// and add the transaction to the back stack so the user can navigate back
			transaction.replace(R.id.content_frame, currentFragment);
			transaction.addToBackStack(null);

			// Commit the transaction
			transaction.commit();

			mDrawerList.setItemChecked(position, true);
			mDrawerLayout.closeDrawers();
		}
	}

	public class AddClickListener implements OnClickListener {
		//to make a new list
		@Override
		public void onClick(View arg0) {
			int listId = newList();
			// Create fragment and give it an argument specifying the article it should show
			currentFragment = new ShoppingListFragment();
			Bundle args = new Bundle();
			args.putInt(ShoppingListFragment.LIST_ID_KEY, listId);
			currentFragment.setArguments(args);
			FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
			// Replace whatever is in the fragment_container view with this fragment,
			// and add the transaction to the back stack so the user can navigate back
			transaction.replace(R.id.content_frame, currentFragment);
			transaction.addToBackStack(null);
			// Commit the transaction
			transaction.commit();
			mDrawerListAdapter.rebuildMap();
			mDrawerList.setItemChecked(0, true);
			mDrawerList.smoothScrollToPosition(0);
			mDrawerLayout.closeDrawers();
		}
	}

	public class DeleteClickListener implements OnClickListener {
		//to delete a list
		private int listId;
		private int deletePosition;

		public DeleteClickListener(int listId, int position){
			this.listId = listId;
			this.deletePosition = position;
		}

		@Override
		public void onClick(View arg0) {
			deleteList(listId);
			int currentPosition = mDrawerList.getCheckedItemPosition();
			int newPosition = currentPosition;
			if(allLists.isEmpty()){
				FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
				// Replace whatever is in the fragment_container view with this fragment,
				// and add the transaction to the back stack so the user can navigate back
				transaction.remove(currentFragment);
				//transaction.addToBackStack(null);
				// Commit the transaction
				transaction.commit();
				return;
			}
			if(deletePosition == currentPosition){
				//if at top of list get fragment underneath
				if(deletePosition == allLists.size()+1){
					newPosition = deletePosition -1;
				}
				// Create fragment and give it an argument specifying the article it should show
				currentFragment = new ShoppingListFragment();
				Bundle args = new Bundle();
				args.putInt(ShoppingListFragment.LIST_ID_KEY, (int) mDrawerListAdapter.getItemId(newPosition-1));
				currentFragment.setArguments(args);
				FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
				// Replace whatever is in the fragment_container view with this fragment,
				// and add the transaction to the back stack so the user can navigate back
				transaction.replace(R.id.content_frame, currentFragment);
				//transaction.addToBackStack(null);
				// Commit the transaction
				transaction.commit();
			}else if(deletePosition < currentPosition){
				newPosition = currentPosition-1;
			}
			mDrawerListAdapter.rebuildMap();
			mDrawerList.setItemChecked(newPosition, true);
		}
	}
}